package com.zhanggm.springcloud.jpa.aop;

import cn.hutool.core.net.Ipv4Util;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.zhanggm.springcloud.jpa.entity.TbUser;
import com.zhanggm.springcloud.jpa.feign.LogApi;
import com.zhanggm.springcloud.jpa.service.TbUserService;
import lombok.extern.slf4j.Slf4j;
import org.aopalliance.intercept.Joinpoint;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.support.RequestContext;
import springfox.documentation.spring.web.json.Json;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.HashMap;
import java.util.Map;

@Configuration
@Slf4j
@Aspect
public class ControllerAspect {

    @Autowired
    private LogApi logApi;

    @Autowired
    private RedisTemplate redisTemplate;
    
    @Autowired
    private TbUserService userService;

    @Pointcut("execution(public * com.zhanggm.springcloud.jpa.controller.*.*(..))")
    public void pointCut(){}

    @Before("pointCut()")
    public void doBefore(JoinPoint joinPoint){

        log.info("ControllerAspect:doBefore");
    }

    @After("pointCut()")
    public void doAfter(JoinPoint joinPoint){
        log.info("ControllerAspect:doAfter");
    }

    @AfterThrowing(value = "pointCut()",throwing = "ex")
    public void doException(JoinPoint joinPoint,Exception ex){
        log.info("ControllerAspect:doException");
    }

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        //返回值
        Object proceed = proceedingJoinPoint.proceed();
        try {
            //类型信息
            String className = proceedingJoinPoint.getTarget().getClass().getName();
            System.out.println(className);
            //方法信息
            MethodSignature methodSignature = (MethodSignature)proceedingJoinPoint.getSignature();
            Method method = methodSignature.getMethod();
            System.out.println(method.getName());
            //方法参数
            Object[] args = proceedingJoinPoint.getArgs();

            if(args!=null)
                System.out.println(JSON.toJSONString(args[0]));
            //方法注解
            GetMapping getMapping = method.getAnnotation(GetMapping.class);
            if(getMapping!=null)
                System.out.println(getMapping.value());
            System.out.println(JSON.toJSONString(proceed));
            //request
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();



            Map<String,Object> logMap = new HashMap<>();
            logMap.put("className",className);
            logMap.put("methodName",method.getName());
            logMap.put("requestParams",JSON.toJSONString(request.getParameterMap()));
            logMap.put("returnValue",JSON.toJSONString(proceed));

            logMap.put("clientIp",getIpAddr(request));

            String token = request.getHeader("token");
            Object userInfoJsonStr = redisTemplate.opsForValue().get(token);
            if(userInfoJsonStr!=null){
                JSONObject jsonObject = JSON.parseObject((String) userInfoJsonStr);
                logMap.put("userId",jsonObject.get("id"));
            }else{
                String username = request.getParameter("username");
                TbUser loginUser = userService.getUserByUsername(username);
                if(loginUser!=null){
                    logMap.put("userId",loginUser.getId());
                }
            }
            logApi.addLog(JSON.toJSONString(logMap));
        }catch (Exception e){
            e.printStackTrace();
        }
        return proceed;
    }


    /**
     * 获取当前网络ip
     * @param request
     * @return
     */
    public static String getIpAddr(HttpServletRequest request){
        String ipAddress = request.getHeader("x-forwarded-for");
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("Proxy-Client-IP");
        }
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getHeader("WL-Proxy-Client-IP");
        }
        if(ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) {
            ipAddress = request.getRemoteAddr();
            if(ipAddress.equals("127.0.0.1") || ipAddress.equals("0:0:0:0:0:0:0:1")){
                //根据网卡取本机配置的IP
                InetAddress inet=null;
                try {
                    inet = InetAddress.getLocalHost();
                } catch (UnknownHostException e) {
                    e.printStackTrace();
                }
                ipAddress= inet.getHostAddress();
            }
        }
        //对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
        if(ipAddress!=null && ipAddress.length()>15){ //"***.***.***.***".length() = 15
            if(ipAddress.indexOf(",")>0){
                ipAddress = ipAddress.substring(0,ipAddress.indexOf(","));
            }
        }
        return ipAddress;
    }
}
